package com.tobe.spring_demo.program_transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * @author yangqifan 2015年9月11日
 * 
 */
@Component
public class UserService {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	@Autowired
	private TransactionTemplate transactionTemplate;
	
	
	public void a(){
		//编程式事务,需要每个类都注入TransactionTemplate, 并在内部类回调中执行事务方法
		
		/**
		 * 执行事务方法原理:
		 * 首先从事务模板中的事务管理器中得到一个TransactionObject,如果connectionHolder的连接为null,说明当前方法没有在事务中运行则根据传播属性
		 * 创建一个事务,doBegin()方法开启一个新事务.
		 * 
		 * 当事务传播属性为REQUIED_NEW, 则挂起当前事务,挂起就把事务对象的连接只为null, 新开一个事务就是在此调用doBegin方法,从dataSource中再获得
		 * 一个连接,新建一个事务对象
		 * 
		 * 估计编程式事务时声明式事务的基础,使用aop或者注解将这里的代码自动生成而已
		 */
		transactionTemplate.execute(new TransactionCallback<Object>() {
			public Object doInTransaction(TransactionStatus status) {
				
				b();
				int i = 4/0;
				c();
				
				return null;
			}
		});
		
		//多个方法需要在事务中执行,这种方式执行,		transactionTemplate是一个TransactionDefiniton的子类,包含隔离级别和传播特性,可能新建一个事务,也可能在原来
		//的事务中继续执行,如果事务传播特性为REQUIRED_NEW, 挂起原来的事务,将原来的事务对象connectionHolder添加在新TransactionStatus对象中(形成一个链表),当新
		//事务执行完毕,继续执行原来的事务
		transactionTemplate.execute(new TransactionCallback<Object>() {
			public Object doInTransaction(TransactionStatus status) {
				
				c();
				
				return null;
			}
		});
		
		//transactionTemplate 所有业务层代码都使用一个数据源, 使用ThreadLocal,每个线程使用dataSource作为key,返回ConnectionHolder
		//当第一次执行事务方法时会创建一个ConnectionHolder并绑定dataSource,当在同一线程中再次调用事务方法,会获取ConnectionHolder,根据
		//事务传播特性判断是否创建新事物还是在 原来的事务中执行
		
		
		//事务模板内部实现和自己写jdbc事务代码一样,catch各种异常并回滚,成功则提交
	}
	
	public void b(){
		jdbcTemplate.execute("insert into meme (age, name) values (222, 'bbbbbb')");
	}
	
	public void c(){
		jdbcTemplate.execute("insert into meme (age, name) values (333, 'ccccc')");
	}
	
	/**
	 * 编程式事务需啊哟使用TransactionTempleate模板来执行事务方法,方法上面使用事务注解,可以在注解上设置传播特性,隔离级别.
	 * 
	 * 这样子事务不用开启和手动提交
	 */
}

